class Animal(object):
	def __init__(self,name,age,classname='Animal'):
		self.__classname = classname
		self.name = name
		self.age = age
	def run(self):
		print('{} is running...'.format(self.__classname))

class Dog(Animal):
    def __init__(self,name,age):
        Animal.__init__(self,name,age,classname='Dog')

class Cat(Animal):
    def __init__(self,name,age):
        Animal.__init__(self,name,age,classname='Cat')
#
#getattr()、setattr()以及hasattr()
dog1 = Dog('大黄',18)
cat1 = Cat('兜兜',5)
animal1 = Animal('未知生物',1);
#dir([obj]):
#调用这个方法将返回包含obj大多数属性名的列表（会有一些特殊的属性不包含在内）。obj的默认值是当前的模块对象。
#hasattr(obj, attr): 
#这个方法用于检查obj是否有一个名为attr的值的属性，返回一个布尔值。
#getattr(obj, attr): 
#调用这个方法将返回obj中名为attr值的属性的值，例如如果attr为’bar’，则返回obj.bar。
#setattr(obj, attr, val):
#调用这个方法将给obj的名为attr的值的属性赋值为val。例如如果attr为’bar’，则相当于obj.bar = val。

print(dir(dog1))
'''
['_Animal__classname', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'run']
输出了一大坨的东西
'''
print(dir(Dog))
'''
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'run']
'''
'''
print(dir(dog1))
print(dir(Dog))
这两个东西进行比较
实例化后的 dog1 要比 Dog对象要多几个属性，这些属性都是在__init__函数中初始化的。
经过测试如果吧 name和age 定义在 init外面，那么这些属性都是可以通过 dir(Dog) 获取到的
'''
print(hasattr(dog1,'name'))		  #输出：True
print(hasattr(dog1,'run'))		  #输出：True


dog1.run()